/*

 * Worker.cpp
 *
 *  Created on: 13/06/2009
 *      Author: banouz
 */

#include "Worker.h"

Worker::Worker(){

}

Worker::~Worker(){

}
//Constructor which receive ones RT as argument

Worker::Worker(map<string, vector<string> >& tMap, string ID) {
	_newMessFlag = 0;
	_isKilled = false;
	_exit = false;

	map<string, vector<string> >::iterator iter;


	for( iter = tMap.begin(); iter != tMap.end(); ++iter ) {
		string tStri = iter->first;
		vector<string> tVec = (*iter).second  ;
		vector<string> tAnsVec;

		for (vector<string>::iterator itVec = tVec.begin(); itVec != tVec.end(); ++itVec) {
			tAnsVec.push_back(*itVec);
		}
		_rTable.insert( make_pair( tStri, tVec ));
	}

	_myID = ID;
	MyMessage *tMyMes= new MyMessage("start",this->getMyID(),0,"",
			&_rTable);
			//_inMBox.push(*tMyMes);
			this->_inMBox.push(tMyMes);

   if (pthread_cond_init(&m_outOfMess, NULL) != 0)
				{
					perror("Quanta cond var initialization");
					exit(1);
				}
}

void Worker::wakeOutOfMess()
   {
	pthread_cond_signal (&m_outOfMess);
   }

void Worker::pushIntoInBox(MyMessage* mess)
   {
	_inMBox.push(mess);
   }

void Worker::run() {

  cout << this->_myID <<"    "<< "working..."<< endl;
//  MyMessage *tMyMes= new MyMessage("start",this->getMyID(),0,"",
//      this->getTable());
  MyMessage *tMyMes= _inMBox.top();

bool tAns = true;
while(true){

  if (!this->getInMBox().empty()){
    cout << this->_myID <<"    "<< "Receiving..."<< endl;
    tAns = this->recv((void **) &tMyMes);
  }
  if (!this->getOutMBox().empty()){
    cout << this->_myID <<"    "<< "Sending..."<< endl;

    tAns = this->send((void *) &tMyMes);
  }
  else{

    cout << this->_myID <<"    "<< "going to sleep..."<< endl;
    pthread_cond_wait(&m_outOfMess, &m_quantaLock2);
    cout << this->_myID <<"    "<< "Waking up..."<< endl;
  }
}
}
  //studentRecv((void **) &tMyMes);
//  sleep(2);
  //studentSend((void *) &tMyMes);



bool Worker::studentSend(void *args){
  cout << this->_myID <<"    "<< "In send...   "<<_outMBox.size()<<"///////////   "<< (this->_outMBox.top())->getFrom() << endl;
  MyMessage* tMess = this->_outMBox.top();
      cout<<"Sec send  "<<(this->_outMBox.top())->getFrom()<<"  to  : " <<(this->_outMBox.top())->getTo()<< endl;

        //pthread_mutex_lock(&m_quantaLock2);
        /*
  if (this->_outMBox.empty()) {
    cout << this->_myID <<"    "<< "In send!!!!!!!!!!!!!!!!...   "<<_outMBox.size()<< endl;
          sleep(1);
         pthread_mutex_unlock(&m_quantaLock2);
          return false;
  }
  else {*/
    //

//    MyMessage *tMyMes= new MyMessage(tSti,this->getMyID(),0,"",
//               &_rTable);
   // _outMailerMBoxRef->push(tMess);this->_outMBox.top()
    _outMailerMBoxRef->push(tMess);
    _outMBox.pop();
    //cout<<"outMailerMBoxRef : "<<_outMailerMBoxRef->size()<<"_outMBox :"<< _outMBox.size()<<endl;

      //}
  //pthread_mutex_unlock(&m_quantaLock2);
  return true;
}

/*bool Worker::studentRecv(void **args){

  if (!this->getInMBox().empty()) {
    MyMessage tMess = this->getInMBox().top();
    if (tMess.getTo().compare("start") == 0) {
      addToMail();
      _inMBox.pop();

    }
    else {
      map<string, vector<string>  >::iterator myIt;
      for(myIt = this->_rTable.begin(); myIt != this->_rTable.end() ; myIt++){
        map<string, vector<string>  >::iterator otherIt = tMess.getRt().find(myIt->first);
        if( (otherIt->second)[0].compare("Infinity") == 0 ) {
          //Do nothing
         	  cout << this->_myID << "  Do nothing "<< endl;
        }else{
          if( ((myIt->second)[0].compare("Infinity") != 0) ||
        		    (otherIt->first.compare(this->_myID) != 0 ) ||
        		  ( atoi(otherIt->second[0].c_str())  < atoi(myIt->second[0].c_str()) ) ){

        	  cout << this->_myID << "  distance from : " << otherIt->first <<" "<<
        	  (atoi(myIt->second.at(0).c_str()))
        			  <<"  Other  dis :  "<<  (atoi(otherIt->second.at(0).c_str())) << endl;

				int tNum = (atoi(otherIt->second.at(0).c_str() )) + 1;
				std::ostringstream osstream;
				osstream << tNum;

				string string_x = osstream.str();
				(myIt->second)[0] = string_x;
				(myIt->second)[1] = (otherIt->first);
          }
          addToMail();
         if(!_inMBox.empty() ){
        	 _inMBox.pop();
         }
        }

      }
    }
  }

else {
 return false;
 }
 return true;
}*/

bool Worker::studentRecv(void **args){

  bool change = false;
  if (!this->getInMBox().empty()) {
    MyMessage* tMess = this->getInMBox_B().top();
    if (tMess->getTo().compare("start") == 0) {
      addToMail();
      _inMBox.pop();

    }
    else {
      map<string, vector<string>  >::iterator myIt;
      for(myIt = this->_rTable.begin(); myIt != this->_rTable.end() ; myIt++){

        map<string, vector<string>  >::iterator otherIt = tMess->getRt().find(myIt->first);
        sleep(1);

        if( ( (( otherIt->second)[2]).compare("Infinity") != 0)) {
          if(((myIt->second)[0].compare("Infinity") != 0)){
            if(  (atoi(otherIt->second[2].c_str()) ) < (atoi(myIt->second[0].c_str()) ) ) {

              /*       cout << this->_myID << "  distance from : " << otherIt->first <<" "<<
                  (atoi(myIt->second.at(0).c_str()))
                                  <<"  Other  dis :  "<<  (atoi(otherIt->second.at(2).c_str())) << endl;
               */
              int tNum = (atoi(otherIt->second.at(2).c_str() )) + 1;
              std::ostringstream osstream;
              osstream << tNum;

              string string_x = osstream.str();

              map<string,vector<string> >::iterator iter = _rTable.find(otherIt->first);
              if( iter != _rTable.end() )
                (iter->second)[0] = string_x;
              (iter->second)[1] = tMess->getFrom();
              cout << this->_myID<<"   update   : "<< "for node: " << iter->first<< "  after  " << iter->second.at(0)
              <<"  From :  "<<tMess->getFrom()<<endl ;
              change = true;
            }
          }

          else {

            /*cout << this->_myID << "  Sec case : distance from : " << otherIt->first <<"  : "<<
                                 myIt->second.at(0).c_str()
                                                  <<"  Other  dis :  "<<  (atoi(otherIt->second.at(2).c_str())) << endl;*/

            int tNum = (atoi(otherIt->second.at(2).c_str() )) + 1;
            std::ostringstream osstream;
            osstream << tNum;
            string string_x = osstream.str();

            map<string,vector<string> >::iterator iter = _rTable.find(otherIt->first);
            if( iter != _rTable.end() )
              (iter->second)[0] = string_x;
            (iter->second)[1] = tMess->getFrom();
            cout << this->_myID<<"  Sec  update   : "<< "for node: " << iter->first<< "  after  " << iter->second.at(0)
            <<"  From :  "<<tMess->getFrom()<<endl ;

            change = true;
          }
        }

      }
    }
  }

  else {
    return false;
  }

  if(!_inMBox.empty() ){
      _inMBox.pop();
    }

  if (change && this->_inMBox.empty()){
    addToMail();
  }


  return true;
}

void Worker::addToMail(){
  map<string,vector<string> >::iterator iter = _graph->find(this->getMyID());
    if( iter != _graph->end() ){
      for (int i = 0; i < (int)iter->second.size(); i++) {
        string tSti = iter->second[i];
        MyMessage *tMyMes= new MyMessage(tSti,this->getMyID(),0,"",
            &_rTable);

        this->_outMBox.push(tMyMes);
        cout<< this->getMyID() <<"   Pushing to : " << tSti <<"   Size   " <<this->_outMBox.size() <<endl;
        }
      }
}


bool Worker::isMailBoxEmpty(){
	  return (_inMBox.empty() && _outMBox.empty());
 }

/////////////////////////////////////////////////////////////////////////////////

int Worker::getNeededQuanta(){
	return ( (_inMBox.size())  + (_outMBox.size()) );
}

///////////////////////////////////////////////////////////////////////////////








